package jfilters.filters.edge;

/*
    Copyright Janne Liljeblad 2008.

    This file is part of JFilters.

    JFilters is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    JFilters is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with JFilters.  If not, see <http://www.gnu.org/licenses/>.
*/

import jfilters.filters.JFilter;
import jfilters.lib.PixelRow;
import jfilters.libmath.JFMath;
import java.util.Arrays;
import java.awt.image.*;
import java.awt.*;

public class JFSobel extends JFilter
{
	//--- Draw params.
	private boolean horizontal = true;
	private boolean vertical = true;
	private boolean keep_sign = true;

	public JFSobel(){}

	public BufferedImage filter( BufferedImage sourceImg, BufferedImage destinationImg )
	{

		WritableRaster destination = destinationImg.getRaster();
		WritableRaster source = sourceImg.getRaster();

		int x1 = 0;
		int y1 = 0;
		int x2 = source.getWidth();
		int y2 = source.getHeight();

		int width  = x2 - x1;
		int height = y2 - y1;

		int bytes = source.getNumBands();
 		boolean alpha = ( bytes == 4 );

		PixelRow pr = prepareRow( source, y1 -1 );// wont be claped
		PixelRow cr = prepareRow( source, y1 );
		PixelRow nr;
		PixelRow dr;
		PixelRow tmp;

  		int counter = 0;
		int row;
		int col;

		int hor_gradient;
		int ver_gradient;

		int gradient;

		/*  loop through the rows, applying the sobel convolution  */
		for (row = y1; row < y2; row++)
		{
			/*  prepare the next row  */
			nr = prepareRow( source, row + 1 );
			dr = prepareRow( destination, row );

			for (col = 0; col < width * bytes; col++)
			{
				hor_gradient = ( horizontal ?
						((pr.getSample(col - bytes) +  2 * pr.getSample(col) + pr.getSample(col + bytes)) -
						(nr.getSample(col - bytes) + 2 * nr.getSample(col) + nr.getSample(col + bytes)))
						: 0);
				ver_gradient = ( vertical ?
						((pr.getSample(col - bytes) + 2 * cr.getSample(col - bytes) + nr.getSample(col - bytes)) -
						(pr.getSample(col + bytes) + 2 * cr.getSample(col + bytes) + nr.getSample(col + bytes)))
						: 0);
				gradient = (vertical && horizontal) ?
				(int) ( Math.round( RMS( (float) hor_gradient, (float) ver_gradient)) / 5.66f) /* always >0 */
				: (int) (keep_sign ? (127 + (Math.round( ( (float) hor_gradient + (float) ver_gradient) / 8.0)))
				: (Math.round( (float) Math.abs( hor_gradient + ver_gradient ) / 4.0)));
			
				//--- Original alpha handling removed.
				if (alpha && (((col + 1) % bytes) == 0))
				{ 	
					/* the alpha channel */
					dr.setSample( col, 255 );
					/*
					*d++ = (counter == 0) ? 0 : 255;
					counter = 0;
					*/
				}
				else
				{
					dr.setSample( col, gradient );
					//if (gradient > 10) counter ++;
				}
			}
			/*  shuffle the row pointers  */
			tmp = pr;
			pr = cr;
			cr = nr;
			nr = tmp;
			
			/*  store the dest  */
			dr.commitData();
		}
		return destinationImg;

	}

	private PixelRow prepareRow( WritableRaster raster, int y )
	{
		y = JFMath.CLAMP( y, 0, raster.getHeight() - 1 );
		return new PixelRow( raster, y, PixelRow.CLAMP_EDGES );
	}

	private static double RMS( double a, double b)
	{
		return Math.sqrt( a * a + b * b );
	}

}//end class